﻿<!-- src/views/login/components/PasswordResetDialog.vue -->
<template>
  <base-dialog
    ref="dialogRef"
    :title="resolvedTitle"
    v-model="innerVisible"
    :close-on-click-modal="false"
    :width="width"
    @cancel="handleCancel"
    @confirm="handleConfirm"
  >
    <!-- 可选自定义顶部提示 -->
    <slot name="notice" />

    <el-form ref="formRef" :model="form" :rules="rules" class="pr-form">
      <!-- 手机号 -->
      <el-form-item prop="mobile">
        <el-input
          size="large"
          v-model.trim="form.mobile"
          :disabled="lockMobile"
          placeholder="请输入手机号"
          autocomplete="off"
          :name="`mobile_${ts}`"
        >
          <template #prefix><base-icon :size="14" name="iconfont-general gen-zhanghao" /></template>
        </el-input>
      </el-form-item>

      <!-- 图形码 -->
      <div v-if="needCaptcha" class="row-2col">
        <el-form-item prop="imgCode" class="grow">
          <el-input
            size="large"
            v-model.trim="form.imgCode"
            placeholder="请输入安全校验码"
            maxlength="4"
            clearable
            autocomplete="off"
            :name="`imgCode_${ts}`"
          >
            <template #prefix><base-icon :size="14" name="iconfont-general gen-yanzhengma" /></template>
          </el-input>
        </el-form-item>

        <el-image class="captcha-img" :src="captchaUrl" fit="contain" @click="refreshCaptcha">
          <template #error><div class="captcha-fallback" @click.stop="refreshCaptcha">点击刷新</div></template>
        </el-image>
      </div>

      <!-- 短信验证码 -->
      <el-form-item v-if="needSms" prop="smsCode">
        <el-input
          size="large"
          v-model.trim="form.smsCode"
          placeholder="请输入验证码"
          maxlength="6"
          autocomplete="one-time-code"
          :name="`sms_${ts}`"
        >
          <template #prefix><base-icon :size="14" name="iconfont-general gen-yanzhengma" /></template>
          <template #suffix>
            <el-button
              text
              @mousedown.prevent
              :disabled="sms.sending || sms.countdown > 0"
              @click="handleSendSms"
              style="width: 80px; color: var(--bd); font-size: 14px"
            >
              {{ sms.countdown > 0 ? `重新获取${sms.countdown}s` : "获取验证码" }}
            </el-button>
          </template>
        </el-input>
      </el-form-item>

      <!-- 新密码 -->
      <el-form-item prop="newPwd">
        <el-input
          size="large"
          v-model="form.newPwd"
          :type="showNew ? 'text' : 'password'"
          maxlength="32"
          :placeholder="pwdPlaceholder"
          show-password
          autocomplete="new-password"
          inputmode="text"
          :name="`newPwd_${ts}`"
          @visible-change="showNew = $event"
        >
          <template #prefix><base-icon :size="14" name="iconfont-general gen-suo" /></template>
        </el-input>
      </el-form-item>

      <!-- 确认密码 -->
      <el-form-item prop="confirmPwd">
        <el-input
          size="large"
          v-model="form.confirmPwd"
          :type="showRe ? 'text' : 'password'"
          maxlength="32"
          placeholder="请再次输入密码"
          show-password
          autocomplete="new-password"
          :name="`confirmPwd_${ts}`"
          @visible-change="showRe = $event"
        >
          <template #prefix><base-icon :size="14" name="iconfont-general gen-suo" /></template>
        </el-input>
      </el-form-item>
    </el-form>
  </base-dialog>
</template>

<script setup>
  import { SMS_TYPE } from "@/utils/const";

  /** 6~16位，且必须同时包含数字、大小写字母（仅字母数字） */
  const PASSWORD_RULE = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[A-Za-z\d]{6,16}$/;

  const props = defineProps({
    modelValue: { type: Boolean, default: false }, // v-model
    scene: { type: String, default: "forgot" }, // 'forgot' | 'first' | 'change'
    title: { type: String, default: "" },
    width: { type: String, default: "404px" },

    mobile: { type: String, default: "" },
    lockMobile: { type: Boolean, default: false },

    needCaptcha: { type: Boolean, default: true },
    needSms: { type: Boolean, default: true },

    // 可覆盖短信类型；默认按场景用重置密码
    smsType: { type: String, default: "" },

    // 可自定义 API（不传用默认 Api.login.*）
    getCaptchaApi: { type: Function, default: null }, // () => Promise<{ cid, imageBase64 }>
    sendSmsApi: { type: Function, default: null }, // (payload) => Promise
    resetApi: { type: Function, default: null }, // (payload) => Promise

    successText: { type: String, default: "" },
  });

  const emit = defineEmits(["update:modelValue", "success", "cancel"]);
  const innerVisible = computed({
    get: () => props.modelValue,
    set: v => emit("update:modelValue", v),
  });

  const resolvedTitle = computed(() => props.title || (props.scene === "first" ? "修改密码" : "忘记密码"));
  const pwdPlaceholder = computed(() => "请设置密码，6~16位，包含数字、大小写字母");
  const resolvedSmsType = computed(() => props.smsType || SMS_TYPE.RESET_PWD);
  const resolvedSuccessText = computed(
    () => props.successText || (props.scene === "first" ? "修改成功，请重新登录" : "重置成功，请使用新密码登录")
  );

  const ts = Date.now();
  const formRef = ref();
  const form = reactive({
    mobile: props.mobile || "",
    imgCode: "",
    smsCode: "",
    newPwd: "",
    confirmPwd: "",
    cid: "",
  });

  const showNew = ref(false);
  const showRe = ref(false);

  /* 倒计时 */
  const sms = reactive({ countdown: 0, sending: false, timer: null });
  function startCountdown(sec = 60) {
    sms.countdown = sec;
    clearInterval(sms.timer);
    sms.timer = setInterval(() => {
      sms.countdown--;
      if (sms.countdown <= 0) {
        clearInterval(sms.timer);
        sms.timer = null;
      }
    }, 1000);
  }
  onBeforeUnmount(() => {
    clearInterval(sms.timer);
    sms.timer = null;
  });

  /* 表单校验（文案对齐原型） */
  const rules = computed(() => {
    const validateMobile = (_, v, cb) => (/^1\d{10}$/.test(v) ? cb() : cb(new Error("手机号格式错误")));
    const validateNewPwd = (_, v, cb) => {
      const val = String(v || "");
      if (!val) return cb(new Error("请输入6~16位，包含数字、大小写字母的密码"));
      if (!PASSWORD_RULE.test(val)) return cb(new Error("请输入6~16位，包含数字、大小写字母的密码"));
      cb();
    };
    const validateConfirm = (_, v, cb) => {
      if (!v) return cb(new Error("请输入与上面一致的密码"));
      if (v !== form.newPwd) return cb(new Error("请输入与上面一致的密码"));
      cb();
    };

    const r = {
      mobile: [
        { required: true, message: "请输入手机号", trigger: "blur" },
        { validator: validateMobile, trigger: "blur" },
      ],
      newPwd: [{ validator: validateNewPwd, trigger: "blur" }],
      confirmPwd: [{ validator: validateConfirm, trigger: "blur" }],
    };

    if (props.needCaptcha) r.imgCode = [{ required: true, message: "请输入安全校验码", trigger: "blur" }];
    if (props.needSms) {
      r.smsCode = [
        { required: true, message: "请输入验证码", trigger: "blur" },
        {
          validator: (_, v, cb) => (/^\d{4,6}$/.test(v || "") ? cb() : cb(new Error("验证码格式错误"))),
          trigger: "blur",
        },
      ];
    }
    return r;
  });

  /* 图形码 */
  const captchaUrl = ref("");
  async function defaultGetCaptcha() {
    const res = await Api.login.GetCodeImg();
    const payload = res?.data ?? res;
    const d = payload?.data ?? payload;
    return { cid: d?.cid || "", imageBase64: d?.imageBase64 || "" };
  }
  async function refreshCaptcha() {
    if (!props.needCaptcha) return;
    try {
      const api = props.getCaptchaApi || defaultGetCaptcha;
      const { cid, imageBase64 } = await api();
      form.cid = cid;
      captchaUrl.value = imageBase64;
    } catch (e) {
      console.error("[PasswordResetDialog] refreshCaptcha:", e);
    }
  }

  /* 短信 */
  async function defaultSendSms(payload) {
    return Api.login.SendSms(payload);
  }
  async function handleSendSms() {
    const fields = ["mobile"];
    if (props.needCaptcha) fields.push("imgCode");
    const ok = await formRef.value
      .validateField(fields)
      .then(() => true)
      .catch(() => false);
    if (!ok) return;
    try {
      sms.sending = true;
      console.error({ mobile: form.mobile, cid: form.cid, code: form.imgCode, type: resolvedSmsType.value });
      debugger;
      await Api.login.SendSms({ mobile: form.mobile, cid: form.cid, code: form.imgCode, type: resolvedSmsType.value });
      $msg?.success?.("验证码已发送");
      startCountdown(60);
    } catch (e) {
      console.error("[PasswordResetDialog] sendSms:", e);
      refreshCaptcha();
    } finally {
      sms.sending = false;
    }
  }

  /* 提交 */
  async function defaultReset(payload) {
    return Api.login.ForgetPass(payload);
  }
  async function handleConfirm() {
    const errors = await formRef.value
      .validate()
      .then(() => null)
      .catch(err => err);
    if (errors) {
      const firstKey = Object.keys(errors)[0];
      const firstMsg = errors[firstKey]?.[0]?.message || "请完善表单";
      $msg?.error?.(firstMsg);
      formRef.value.scrollToField?.(firstKey);
      return;
    }
    try {
      const api = props.resetApi || defaultReset;
      await api({ mobile: form.mobile, code: form.smsCode, password: form.newPwd });
      $msg?.success?.(resolvedSuccessText.value);
      emit("success", { mobile: form.mobile, scene: props.scene });
      resetOnClose();
      innerVisible.value = false;
    } catch (e) {
      console.error("[PasswordResetDialog] reset:", e);
      refreshCaptcha();
    }
  }
  function handleCancel() {
    resetOnClose();
    emit("cancel");
  }

  /* 打开/关闭 */
  watch(
    () => innerVisible.value,
    v => {
      if (v) {
        if (props.mobile) form.mobile = props.mobile;
        refreshCaptcha();
      } else {
        resetOnClose();
      }
    },
    { immediate: true }
  );

  function resetOnClose() {
    formRef.value?.resetFields?.();
    form.imgCode = "";
    form.smsCode = "";
    form.newPwd = "";
    form.confirmPwd = "";
    captchaUrl.value = "";
    clearInterval(sms.timer);
    sms.timer = null;
    sms.countdown = 0;
  }
</script>

<style scoped>
  .pr-form {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  .row-2col {
    display: flex;
    gap: 12px;
    align-items: center;
    margin-bottom: 18px;
  }
  .grow {
    flex: 1;
    margin-bottom: 0;
  }
  .captcha-img {
    width: 120px;
    height: 40px;
    cursor: pointer;
  }
  .captcha-fallback {
    width: 120px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f5;
    color: #999;
  }
</style>
